﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace Tank_Control
{    
    public partial class ControlForm : Form
    {
        int ActiveDirections = 0; // Активные направления движения
        TankDevice Device; // Обложка общения с устройством
        // Переменные статистики движения
        int LeftPath = 0;
        int LeftSpeed = 0;
        int RightPath = 0;
        int RightSpeed = 0;

        public ControlForm()
        {            
            InitializeComponent();

            try
            { 
                Device = new TankDevice(9600, 100, 100);
                Device.LogMsg += new WriteMsgToLog(ConsoleAppendThreadSafe);
                LeftSpeedTrack.Value = 1000;
                RightSpeedTrack.Value = 1000;
                RefreshTimer.Enabled = true;
                ConsoleAppend("Девайс успешно подключен (" + Device.PortName + ")", ConsoleMessageType.Info);
            }
            catch (Exception ex)
            {
                ConsoleAppend(ex.Message, ConsoleMessageType.Error);
            }
        }

        private void ConsoleAppendThreadSafe(string msg, ConsoleMessageType msg_type)
        {
            this.Invoke(new WriteMsgToLog(ConsoleAppend), msg, msg_type);
        }

        private void ConsoleAppend(string msg, ConsoleMessageType msg_type)
        {
            Color color = Color.Black;
            string tag = "";
            
            switch (msg_type)
            {
                case ConsoleMessageType.Info:
                    color = Color.Green;
                    tag = "INFO: ";
                    break;
                case ConsoleMessageType.Warning:
                    color = Color.Blue;
                    tag = "WARNING: ";
                    break;
                case ConsoleMessageType.Error:
                    color = Color.Red;
                    tag = "ERROR: ";
                    break;
            }
            string line = tag + msg + Environment.NewLine;
            int old_console_len = ConsoleBox.Text.Length;
            ConsoleBox.Select(Int32.MaxValue, 0);
            ConsoleBox.AppendText(line);
            ConsoleBox.Select(old_console_len, ConsoleBox.Text.Length);
            ConsoleBox.SelectionColor = color;
            ConsoleBox.Select(Int32.MaxValue, 0);
        }

        // Обновление статистики по таймеру
        private void RefreshTimer_Tick(object sender, EventArgs e)
        {
            // Устанавливаем текущие значения
            LeftPathBox.Text = LeftPath.ToString() + "мм";
            RightPathBox.Text = RightPath.ToString() + "мм";
            LeftSpeedBox.Text = LeftSpeed.ToString() + "мм/c";
            RightSpeedBox.Text = RightSpeed.ToString() + "мм/c";
            // Делаем запросы на получение новой статистики
            try
            {
                Device.ExecuteCommand("p1", UpdateLeftPath);
                Device.ExecuteCommand("p2", UpdateRightPath);
                Device.ExecuteCommand("g1", UpdateLeftSpeed);
                Device.ExecuteCommand("g2", UpdateRightSpeed);
            }
            catch (Exception ex)
            {
                ConsoleAppend(ex.Message, ConsoleMessageType.Error);
                RefreshTimer.Enabled = false;
                return;
            }
        }

        // Обработчики ответов девайса на команды обновления статистики
        private void UpdateLeftPath(string arg)
        {
            LeftPath = Convert.ToInt32(arg, 16);
        }
        private void UpdateRightPath(string arg)
        {
            RightPath = Convert.ToInt32(arg, 16);
        }
        private void UpdateLeftSpeed(string arg)
        {
            LeftSpeed = Convert.ToInt32(arg, 16);
        }
        private void UpdateRightSpeed(string arg)
        {
            RightSpeed = Convert.ToInt32(arg, 16);
        }
        
        // Обработчики нажатия клавиш на форме для управления направлением движения
        private void ControlForm_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode == Keys.Up)
                KeyBox_MouseDown(UpKeyBox, null);
            if (e.KeyCode == Keys.Down)
                KeyBox_MouseDown(DownKeyBox, null);
            if (e.KeyCode == Keys.Left)
                KeyBox_MouseDown(LeftKeyBox, null);
            if (e.KeyCode == Keys.Right)
                KeyBox_MouseDown(RightKeyBox, null);
            e.Handled = true;
        }
        private void ControlForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up)
                KeyBox_MouseUp(UpKeyBox, null);
            if (e.KeyCode == Keys.Down)
                KeyBox_MouseUp(DownKeyBox, null);
            if (e.KeyCode == Keys.Left)
                KeyBox_MouseUp(LeftKeyBox, null);
            if (e.KeyCode == Keys.Right)
                KeyBox_MouseUp(RightKeyBox, null);
            e.Handled = true;
        }
        // Обработчики кликов мыши для кнопок выбора направления
        private void KeyBox_MouseDown(object sender, MouseEventArgs e)
        {
            Label key_box = sender as Label;
            key_box.BackColor = Color.Lime;
            int box_tag = Convert.ToInt32(key_box.Tag);
            UpdateDirections(ActiveDirections | box_tag);
        }
        private void KeyBox_MouseUp(object sender, MouseEventArgs e)
        {
            Label key_box = sender as Label;
            key_box.BackColor = Color.LightGray;
            int box_tag = Convert.ToInt32(key_box.Tag);
            UpdateDirections(ActiveDirections & ~box_tag);
        }

        // Обновление направлений движения
        private void UpdateDirections(int new_dir)
        {
            if (new_dir != ActiveDirections)
            {
                Int16 left_speed = 0;
                Int16 right_speed = 0;
                ActiveDirections = new_dir;
                switch (new_dir)
                {
                    case 1: // Нажата "вперед" - едем вперед
                        left_speed = (Int16)LeftSpeedTrack.Value;
                        right_speed = (Int16)RightSpeedTrack.Value;
                        break;
                    case 2: // Нажата "назад" - едем назад
                        left_speed = (Int16)(-LeftSpeedTrack.Value);
                        right_speed = (Int16)(-RightSpeedTrack.Value);
                        break;
                    case 4: // Нажата "влево" - разворот на месте обеими гусеницами через левый бок
                        left_speed = (Int16)(-LeftSpeedTrack.Value);
                        right_speed = (Int16)RightSpeedTrack.Value;
                        break;
                    case 5: // Нажата "влево" и "вперед" - поворот передом влево (на неподвижной левой гусенице)
                        left_speed = 0;
                        right_speed = (Int16)RightSpeedTrack.Value;
                        break;
                    case 6: // Нажата "влево" и "назад" - поворот задом влево (на неподвижной левой гусенице)
                        left_speed = 0;
                        right_speed = (Int16)(-RightSpeedTrack.Value);
                        break;
                    case 8: // Нажата "вправо" - разворот на месте обеими гусеницами через правый бок
                        left_speed = (Int16)LeftSpeedTrack.Value;
                        right_speed = (Int16)(-RightSpeedTrack.Value);
                        break;
                    case 9: // Нажата "вправо" и "вперед" - поворот передом вправо (на неподвижной правой гусенице)
                        left_speed = (Int16)LeftSpeedTrack.Value;
                        right_speed = 0;
                        break;
                    case 10: // Нажата "вправо" и "назад" - поворот задом вправо (на неподвижной правой гусенице)
                        left_speed = (Int16)(-LeftSpeedTrack.Value);
                        right_speed = 0;
                        break;
                }
                try
                {
                    Device.SetSpeeds(left_speed, right_speed);
                }
                catch (Exception ex)
                {
                    ConsoleAppend("Похоже девайс отвалился (требуется перезапуск программы)", ConsoleMessageType.Error);
                    RefreshTimer.Enabled = false;
                    return;
                }    
            }
        }
        // Если форма закрывается надо остановить обновление статистики и всякие коммуникации с девайсом
        private void ControlForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            RefreshTimer.Enabled = false;
        }

        private void RightKeyBox_Click(object sender, EventArgs e)
        {

        }
    }
}
